package com.xiaoshuidi.cloud.module.report.xxljob;

import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.module.report.constant.ContractStatusEnum;
import com.xiaoshuidi.cloud.module.report.constant.PublicUseConstant;
import com.xiaoshuidi.cloud.module.report.convert.finance.OwnerCollectInAdvanceConvert;
import com.xiaoshuidi.cloud.module.report.dal.DO.ContractHouseOwnerDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.OwnerCollectInAdvanceDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.OwnerIncomeDetailReportDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.ReportOwnerContractDayRentDO;
import com.xiaoshuidi.cloud.module.report.dal.mapper.ContractHouseOwnerMapper;
import com.xiaoshuidi.cloud.module.report.dal.mapper.ContractRentorderMapper;
import com.xiaoshuidi.cloud.module.report.dal.mapper.report.OwnerIncomeDetailDayReportMapper;
import com.xiaoshuidi.cloud.module.report.service.contract.ContractOperateService;
import com.xiaoshuidi.cloud.module.report.service.finance.OwnerCollectInAdvanceService;
import com.xiaoshuidi.cloud.module.report.service.finance.OwnerIncomeDetailReportService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 预付报表 job 每日4：30点跑一次
 *
 */
@Component
@Slf4j
public class OwnerCollectInAdvanceHandleJob {

    DateTimeFormatter monthFormat =DateTimeFormatter.ofPattern("yyyy年MM月");

    @Resource
    private OwnerCollectInAdvanceService ownerCollectInAdvanceService;
    @Resource
    private ContractOperateService contractOperateService;
    @Resource
    private ContractRentorderMapper contractRentorderMapper;
    @Resource
    private ContractHouseOwnerMapper contractHouseOwnerMapper;
    @Resource
    private OwnerIncomeDetailReportService ownerIncomeDetailReportService;
    @Resource
    private OwnerIncomeDetailDayReportMapper detailDayReportMapper;

    @XxlJob("ownerCollectInAdvanceHandleJob")
    @TenantIgnore
    public void execute() {
        DateTimeFormatter df =DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String params = XxlJobHelper.getJobParam();
        LocalDate yesterday = LocalDate.now().minusDays(1);
        if(StringUtils.isNotBlank(params)){
            try {
                yesterday = LocalDate.parse(params, df);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        //获取昨天存在权责的业主合同  业主合同目前较少可以一次处理
        List<ContractHouseOwnerDO> contractHouseOwnerDOS = contractHouseOwnerMapper.selectActiveByDate(yesterday);
        handlerAdvance(contractHouseOwnerDOS, yesterday);
    }

    /**
     * 处理预收明细项
     */
    public void handlerAdvance(List<ContractHouseOwnerDO> infoDOList,LocalDate yesterday){
        String lastMonth = yesterday.minusMonths(1).format(monthFormat);
        String statisMonth = yesterday.format(monthFormat);
        LocalDateTime endTime = yesterday.atTime(23,59);
        LocalDateTime startTime = yesterday.atTime(0,0);
        LocalDateTime firstDayTime = yesterday.with(TemporalAdjusters.firstDayOfMonth()).atTime(0,0);
        List<OwnerCollectInAdvanceDO> advanceDOList = new ArrayList<>();
        for (ContractHouseOwnerDO ownerDO : infoDOList) {
            //上月期末余额是本月期初余额  只统计算租金的
            List<OwnerCollectInAdvanceDO> collectInAdvanceDOList = ownerCollectInAdvanceService.selectRentAdvanceByContractIdAndMonth(ownerDO.getId());
            //本月结转=本月实际发生的权责房租、能耗、一次性费用的累计
            OwnerIncomeDetailReportDO incomeDetail = ownerIncomeDetailReportService.selectDetailsByContractIdInCurrentMonth(ownerDO.getId(),statisMonth);
            OwnerCollectInAdvanceDO advanceDO = OwnerCollectInAdvanceConvert.INSTANCE.convertDetail2Advance(incomeDetail);
            if(advanceDO==null){
                continue;
            }
            advanceDO.setActualRefundAmount(BigDecimal.ZERO);
            advanceDO.setId(null);
            /**
             *   期初余额：上月期末余额||本月租金收入
             *   本月新增：各种账单实收金额
             *   本月结转：累计权责收入
             *   期末余额：上月期末余额 +本月新增 -本月结转 || 各种账单实收金额+预充值 -本月结转
             */
            //处理在租状态
            if(ContractStatusEnum.ACTIVE.getStatus().equals(ownerDO.getContractStatus())){
                advanceDO.setRentStatus(PublicUseConstant.RENT_IN);
            }else if (ContractStatusEnum.NORMAL_END.getStatus().equals(ownerDO.getContractStatus())||
                    ContractStatusEnum.ABNORMAL_END.getStatus().equals(ownerDO.getContractStatus())){
                advanceDO.setRentStatus(PublicUseConstant.RENT_OUT);
            }

            if(CollectionUtils.isEmpty(collectInAdvanceDOList)){
                /**
                 * 之前没有预收数据
                 * 1、系统上线之初  初始化数据  所有的合同账单支付金额-已发生租金权责-已发生水电权责
                 * 2、补录合同  同上
                 *  上面两个   合同创建时间在合同开始时间之后
                 */
                //查询所有已支付账单和已充值金额  本月支付的不算在内，本月支付会在本月新增里
                BigDecimal sumRent = contractRentorderMapper.sumOwnerAllAmountByContractId(ownerDO.getId(),firstDayTime);
                sumRent = sumRent==null?BigDecimal.ZERO:sumRent;
                //查询合同的租金权责
                BigDecimal sumPower = ownerIncomeDetailReportService.sumTotalRentAndWaterByContractId(ownerDO.getId());
                sumPower = sumPower==null?BigDecimal.ZERO:sumPower;
                advanceDO.setOpeningBalance(sumRent.subtract(sumPower));
                /**
                 * 本月结转 如果不是补录合同 直接就是本月权责
                 * 补录合同 需去除之前月份的权责，只统计本月的
                 */
                //昨天当天的本月结转
                handleAdditionalCarry(advanceDO,yesterday);
//                if(!ownerDO.getStartTime().isBefore(startTime.with(TemporalAdjusters.firstDayOfMonth()).toLocalDate())){
                    //如果是本月的补录 补录合同的期初余额不算本月结转 多减了 需要补回来
                    advanceDO.setOpeningBalance(advanceDO.getOpeningBalance().add(advanceDO.getCurCarryForward()));
//                }
            }else {
                //不是补录合同
                OwnerIncomeDetailReportDO ownerIncomeDetailReportDO = detailDayReportMapper.selectLastOneByContractID(ownerDO.getId());
                if(ownerIncomeDetailReportDO!=null){
                    advanceDO.setCurCarryForward(ownerIncomeDetailReportDO.getCurRentReduce());
                }

                //期初余额是上月期末余额 本月合同新增不算在内
                for (OwnerCollectInAdvanceDO collectInAdvanceDO : collectInAdvanceDOList) {
                    if(collectInAdvanceDO.getStatisticsMonth().equals(statisMonth)){
                        advanceDO.setOpeningBalance(collectInAdvanceDO.getOpeningBalance());
                        advanceDO.setCurCarryForward(advanceDO.getCurCarryForward().add(collectInAdvanceDO.getCurCarryForward()));
                    }else if(collectInAdvanceDO.getStatisticsMonth().equals(lastMonth)){
                        advanceDO.setOpeningBalance(collectInAdvanceDO.getEndingBalance());
                    }
                }
            }
            //本月新增 本月账单费用
            BigDecimal curAmount = contractRentorderMapper.sumOwnerAmountByContractIdAndTime(ownerDO.getId(), startTime.with(TemporalAdjusters.firstDayOfMonth()), endTime);
            curAmount = curAmount==null?BigDecimal.ZERO:curAmount;
            advanceDO.setCurNewAdd(curAmount);
            //期末余额
            advanceDO.setEndingBalance(advanceDO.getOpeningBalance().add(advanceDO.getCurNewAdd()).subtract(advanceDO.getCurCarryForward()).subtract(advanceDO.getActualRefundAmount()));
            advanceDOList.add(advanceDO);
        }
        //查询当月是否已经生成过预收明细收入
        List<Long> contractIds = advanceDOList.stream().map(OwnerCollectInAdvanceDO::getContractId).collect(Collectors.toList());
        List<OwnerCollectInAdvanceDO> inAdvanceDOList = ownerCollectInAdvanceService.selectDetailsInCurrentMonth(statisMonth,contractIds);
        if (CollectionUtils.isEmpty(inAdvanceDOList)) {
            ownerCollectInAdvanceService.batchInsert(advanceDOList);
        }else {
            //不为空则修改
            advanceDOList.forEach(e->{
                inAdvanceDOList.forEach(report->{
                    if(e.getContractId().equals(report.getContractId())){
                        e.setId(report.getId());
                    }
                });
            });
            List<OwnerCollectInAdvanceDO> updateList = advanceDOList.stream().filter(e -> e.getId() != null).collect(Collectors.toList());
            List<OwnerCollectInAdvanceDO> insertList = advanceDOList.stream().filter(e -> e.getId() == null).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(updateList)) {
                ownerCollectInAdvanceService.batchUpdate(updateList);
            }
            if (CollectionUtils.isNotEmpty(insertList)) {
                ownerCollectInAdvanceService.batchInsert(insertList);
            }
        }
    }

    private void handleAdditionalCarry(OwnerCollectInAdvanceDO advanceDO,LocalDate yesterday){
        DateTimeFormatter formatter =DateTimeFormatter.ofPattern("yyyyMMdd");
        //查询合同日租金
        List<ReportOwnerContractDayRentDO> dayRentList = contractOperateService.selectOwnerListByContractId(advanceDO.getContractId());
        //获取昨天所在月份
        int yesterdayLength = yesterday.lengthOfMonth();
        int lastMonthLength = yesterday.minusMonths(1).lengthOfMonth();
        ReportOwnerContractDayRentDO yesterdayMonth = new ReportOwnerContractDayRentDO();
        ReportOwnerContractDayRentDO lastDayMonth = new ReportOwnerContractDayRentDO();
        for (ReportOwnerContractDayRentDO dayRentDO : dayRentList) {
            if (yesterdayLength == dayRentDO.getMonthDays()) {
                yesterdayMonth = dayRentDO;
            }
            if (lastMonthLength == dayRentDO.getMonthDays()) {
                lastDayMonth = dayRentDO;
            }
        }
        //TODO 考虑目前很多都是管家没有进行合同退租，且业主不存在逾期场景，避免频繁修改数据，故如果合同过期了将不在计算当天结转
        ContractHouseOwnerDO contractRoomDO = contractHouseOwnerMapper.selectById(advanceDO.getContractId());
        if(contractRoomDO.getEndTime().isBefore(yesterday)){
            advanceDO.setCurCarryForward(BigDecimal.ZERO);
            return;
        }

        if(contractRoomDO.getEvictionTime()!=null&&yesterday.isAfter(contractRoomDO.getEvictionTime())){
            //此种情况是提前退租了
            advanceDO.setCurCarryForward(BigDecimal.ZERO);
            return;
        }
        //获取开始日期所在的天数
        int daysOfStartTime = contractRoomDO.getStartTime().getDayOfMonth();

        BigDecimal rentReduce = BigDecimal.ZERO;
        /**
         * 循环判断从1号到昨天的日租金，当天是否在免租期 累加就是本月结转
         */
        //根据合同所在天数计算合同日租金和优惠金额
        //判断是否在免租期内 循环判断从本月1号到昨天
        String rentFreePeriod = yesterdayMonth.getRentFreePeriod();
        if(daysOfStartTime>yesterday.getDayOfMonth()){
            // 8月10号： 7月份的日租金*10
            rentReduce = lastDayMonth.getNormalDayRent();
        }else if(daysOfStartTime==yesterday.getDayOfMonth()){
            //8月14号:
            rentReduce = lastDayMonth.getDayRentBalance();
        }else{
            rentReduce =yesterdayMonth.getNormalDayRent();
        }
        if (StringUtils.isNotBlank(rentFreePeriod)) {
            for (String s : rentFreePeriod.split(",")) {
                String[] split = s.split("~");
                LocalDate start = LocalDate.parse(split[0], formatter);
                LocalDate end = LocalDate.parse(split[1], formatter);
                if (!start.isAfter(yesterday) && !end.isBefore(yesterday)) {
                    rentReduce =BigDecimal.ZERO;
                    break;
                }
            }
        }
        advanceDO.setCurCarryForward(rentReduce);
    }

}